package com.anmong.cloud.cloudcommon.util;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.protocol.HTTP;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.*;
import java.io.*;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Map;

/**
 * @author songwenlong
 * 2017/7/13
 */
@Slf4j
public class HttpsClientUtils {


    /**
     * 获取完整的returnbody
     *
     * @param url
     * @return
     */
    public static JSONObject sendGet(String url) {
        HttpUriRequest request = RequestBuilder.get(url).setHeader("Accept", "application/json").build();
        return getResponseJSONBody(request);
    }

    public static JSONObject sendGet(String url, Map<String,Object> param) {
        String urlNameString = url;
        //增加参数
        if(param!=null&&param.size()>0){
            urlNameString = urlNameString+"?";
            for(String key : param.keySet()){
                urlNameString = urlNameString + key + "=" + param.get(key) + "&";
            }
            urlNameString = urlNameString.substring(0,urlNameString.length() -1);
        }
        RequestConfig requestConfig = RequestConfig.custom()
                //设置从connect Manager(连接池)获取Connection 超时时间，单位毫秒。这个属性是新加的属性，因为目前版本是可以共享连接池的。
                .setConnectionRequestTimeout(1000)
                //请求获取数据的超时时间(即响应时间)，单位毫秒。 如果访问一个接口，多少时间内无法返回数据，就直接放弃此次调用。
                .setSocketTimeout(30000)
                //设置连接超时时间，单位毫秒。
                .setConnectTimeout(30000)
                .build();
        HttpUriRequest request = RequestBuilder.get(urlNameString)
                .setHeader("Accept", "application/json")
                .setConfig(requestConfig)
                .build();
        return getResponseJSONBody(request);
    }
    public static JSONArray sendGetJSONArray(String url, Map<String,Object> param) {
        String urlNameString = url;
        //增加参数
        if(param!=null&&param.size()>0){
            urlNameString = urlNameString+"?";
            for(String key : param.keySet()){
                urlNameString = urlNameString + key + "=" + param.get(key) + "&";
            }
            urlNameString = urlNameString.substring(0,urlNameString.length() -1);
        }
        RequestConfig requestConfig = RequestConfig.custom()
                //设置从connect Manager(连接池)获取Connection 超时时间，单位毫秒。这个属性是新加的属性，因为目前版本是可以共享连接池的。
                .setConnectionRequestTimeout(1000)
                //请求获取数据的超时时间(即响应时间)，单位毫秒。 如果访问一个接口，多少时间内无法返回数据，就直接放弃此次调用。
                .setSocketTimeout(30000)
                //设置连接超时时间，单位毫秒。
                .setConnectTimeout(30000)
                .build();
        HttpUriRequest request = RequestBuilder.get(urlNameString)
                .setHeader("Accept", "application/json")
                .setConfig(requestConfig)
                .build();
        return getResponseJSONArrayBody(request);
    }


    /**
     * 获取完整的returnbody
     *
     * @param url
     * @return
     */
    public static JSONObject sendPost(String url) {
        HttpPost post = new HttpPost(url);
        post.setHeader("Accept", "application/json");
        return getResponseJSONBody(post);
    }


    /**
     * 获取完整的returnbody
     *
     * @param request 请求体
     * @return
     */
    public static JSONObject getResponseJSONBody(HttpUriRequest request) {

        CloseableHttpClient client = null;
        CloseableHttpResponse response = null;

        try {
            client = createSSLClientDefault();
            response = client.execute(request);
            HttpEntity entity = response.getEntity();
            String responseEntity = EntityUtils.toString(entity, "utf-8");
            EntityUtils.consume(entity);
            return JSON.parseObject(responseEntity);
        } catch (Exception e) {
            log.error("解析请求出错:",e);
            return new JSONObject();
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
                if (client != null) {
                    client.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 获取完整的returnbody
     *
     * @param request 请求体
     * @return
     */
    public static JSONArray getResponseJSONArrayBody(HttpUriRequest request) {

        CloseableHttpClient client = null;
        CloseableHttpResponse response = null;

        try {
            client = createSSLClientDefault();
            response = client.execute(request);
            HttpEntity entity = response.getEntity();
            String responseEntity = EntityUtils.toString(entity, "utf-8");
            EntityUtils.consume(entity);
            return JSON.parseArray(responseEntity);
        } catch (Exception e) {
            log.error("解析请求出错:",e);
            return new JSONArray();
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
                if (client != null) {
                    client.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private static class TrustAnyTrustManager implements X509TrustManager {

        public void checkClientTrusted(X509Certificate[] chain, String authType)
                throws CertificateException {
        }

        public void checkServerTrusted(X509Certificate[] chain, String authType)
                throws CertificateException {
        }

        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[]{};
        }
    }

    private static class TrustAnyHostnameVerifier implements HostnameVerifier {
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    }

    /**
     * post方式请求服务器(https协议)
     *
     * @param url     请求地址
     * @param param   参数
     * @param charset 编码
     * @return
     * @throws NoSuchAlgorithmException
     * @throws KeyManagementException
     * @throws IOException
     */
    public static String sendPost(String url, String param, String charset) throws Exception {
        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, new TrustManager[]{new TrustAnyTrustManager()}, new java.security.SecureRandom());

        URL console = new URL(url);
        HttpsURLConnection conn = (HttpsURLConnection) console.openConnection();
        conn.setSSLSocketFactory(sc.getSocketFactory());
        conn.setHostnameVerifier(new TrustAnyHostnameVerifier());
        conn.setDoOutput(true);
        conn.connect();
        DataOutputStream out = new DataOutputStream(conn.getOutputStream());
        out.write(param.getBytes(charset));
        // 刷新、关闭
        out.flush();
        out.close();
        InputStream is = conn.getInputStream();
        if (is != null) {
            ByteArrayOutputStream outStream = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = is.read(buffer)) != -1) {
                outStream.write(buffer, 0, len);
            }
            is.close();
            return new String(outStream.toByteArray());
        }
        return null;
    }

    public static CloseableHttpClient createSSLClientDefault() {
        try {
            //使用 loadTrustMaterial() 方法实现一个信任策略，信任所有证书
            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
                // 信任所有
                public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                    return true;
                }
            }).build();
            //NoopHostnameVerifier类:  作为主机名验证工具，实质上关闭了主机名验证，它接受任何
            //有效的SSL会话并匹配到目标主机。
            HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
            return HttpClients.custom().setSSLSocketFactory(sslsf).build();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        }
        return HttpClients.createDefault();

    }

    public static JSONObject sendPostJson(String URL,JSONObject param) {
        JSONObject json = new JSONObject();
        CloseableHttpClient client = HttpClients.createDefault();
        HttpPost post = new HttpPost(URL);
        post.setHeader("Content-Type", "application/json");
        RequestConfig requestConfig = RequestConfig.custom()
                //设置从connect Manager(连接池)获取Connection 超时时间，单位毫秒。这个属性是新加的属性，因为目前版本是可以共享连接池的。
                .setConnectionRequestTimeout(1000)
                //请求获取数据的超时时间(即响应时间)，单位毫秒。 如果访问一个接口，多少时间内无法返回数据，就直接放弃此次调用。
                .setSocketTimeout(30000)
                //设置连接超时时间，单位毫秒。
                .setConnectTimeout(30000)
                .build();
        post.setConfig(requestConfig);
        String result;
        try {
            StringEntity s = new StringEntity(param.toJSONString(), "utf-8");
            s.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE,
                    "application/json"));
            post.setEntity(s);
            // 发送请求
            HttpResponse httpResponse = client.execute(post);
            // 获取响应输入流
            InputStream inStream = httpResponse.getEntity().getContent();
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    inStream, "utf-8"));
            StringBuilder stringBuilder = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null)
                stringBuilder.append(line + "\n");
            inStream.close();
            result = stringBuilder.toString();
            if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                json = JSONObject.parseObject(result);
            } else {
                log.error("post请求服务器业务返回错误:",result);
                //System.out.println("请求服务端失败");
            }
        } catch (Exception e) {
            //logger.error("请求异常："+e.getMessage());
            log.error("post请求服务器出错:",e);
        }
        return json;
    }


}
